#include <TimerOne.h>


/* =====================================
 * PWM part (not using Ardu functions)
 * =====================================*/
#define MAX_DUTY 100


static struct {
  uint8_t state;              // high or low
  uint16_t freq;
  uint16_t period;
  uint16_t duration[2];       // duration of high or low
} g_pwmInfo;


void PWM_Init(uint16_t freq){
  g_pwmInfo.freq = freq;
  g_pwmInfo.period = 1000L*1000L / freq;
  Timer1.initialize(g_pwmInfo.period);
}


void PWM_Set(uint8_t duty) {
  uint32_t dura = (uint32_t)g_pwmInfo.period * duty / MAX_DUTY;
  g_pwmInfo.duration[1] = dura;  // high duration
  g_pwmInfo.duration[0] = g_pwmInfo.period - dura;
}


/* =====================================
 * BLDC part (using Ardu functions)
 * =====================================*/
#define INH_A  2
#define INH_B  4
#define INH_C  6
const int INH[] = {INH_A, INH_B, INH_C};
const int IN[] = {3,5,7};

static struct {
  uint8_t inh[3];
  uint8_t in[3];
} bldc_state;

int g_count = 0;
static void PWM_Toggle(){
  g_count ++;
  
  noInterrupts();
  uint8_t _state = ! (g_pwmInfo.state);  // toggle state
  g_pwmInfo.state = _state;
  Timer1.setPeriod(g_pwmInfo.duration[_state]);  // duration on this state
  interrupts();

  // output
  uint8_t _level;
  for (byte i=0; i<3; i++) {
    _level = _state && (bldc_state.inh[i]);
    digitalWrite(INH[i], _level);
  }
}


void Print_Info() {
  Serial.print("freq:"); Serial.println(g_pwmInfo.freq);
  Serial.print("state:"); Serial.println(g_pwmInfo.state);
  Serial.print("period:"); Serial.println(g_pwmInfo.period);
  Serial.print("duration:"); 
  Serial.print(g_pwmInfo.duration[0]); Serial.print(",");
  Serial.println(g_pwmInfo.duration[1]);
}


void setup() {  
  PWM_Init(5000);
  PWM_Set(50);
  Timer1.attachInterrupt(PWM_Toggle);

  for (int i=0; i<3; i++){
    pinMode(INH[i], OUTPUT);
    pinMode(IN[i], OUTPUT); digitalWrite(IN[i], LOW);
  }
 
  Serial.begin(115200);
  Print_Info();
}


void loop() {
  bldc_state.inh[0] = !(bldc_state.inh[0]);
  bldc_state.inh[1] = !(bldc_state.inh[1]);
  delay(200);
  Serial.println(g_count);
}
